#pragma once

namespace EGlib
{
  class ProcessRunner
  {
  public:
    void setup();
    void cleanup();
    
    static void on_process_quitted(GPid pid,gint status,gpointer data);
    
    int spawn_sync();
    
    Glib::RefPtr<Process>             proc;
    
    Glib::RefPtr<Glib::MainLoop>      main_loop;
    Glib::RefPtr<Glib::MainContext>   main_context;
    
    GPid                              pid;
    gint                              stdin_fd;
    gint                              stdout_fd;
    gint                              stderr_fd;
    
    Glib::RefPtr<Glib::IOChannel>     stdin_pipe;
    Glib::RefPtr<Glib::IOChannel>     stdout_pipe;
    Glib::RefPtr<Glib::IOChannel>     stderr_pipe;
    
    char*                             input_buffer;
    int                               input_buffer_size;
    int                               input_data_size;
    int                               input_read_ptr;

    gint                              status;

    std::vector<gchar*>               envp;
    
    bool on_stdin_wanted(Glib::IOCondition condition);
    bool on_stdout_available(Glib::IOCondition condition);
    bool on_stderr_available(Glib::IOCondition condition);
    static bool on_output_available(
      Glib::RefPtr<Glib::IOChannel> pipe,
      Glib::RefPtr<IProcessOutputHandler> output_handler);
  };
  
  class OutputToGIOChannel : public IProcessOutputHandler
  {
  public:
    OutputToGIOChannel(Glib::RefPtr<Glib::IOChannel> channel);
    
    virtual void handle_output(char *buffer,int size);
    
  private:
    Glib::RefPtr<Glib::IOChannel> channel;
  };
  
  class InputFromGIOChannel : public IProcessInputProvider
  {
  public:
    InputFromGIOChannel(Glib::RefPtr<Glib::IOChannel> channel);
    
    virtual void provide_input(char *buffer,int max_size,int &actual_size_provided);
  
  private:
    Glib::RefPtr<Glib::IOChannel> channel;
  };
}

#ifdef GOGU
/*
 * Macros to test the exit status returned by wait
 * and extract the relevant values.
 */
#ifdef _POSIX_SOURCE
#define	_W_INT(i)	(i)
#else
#define	_W_INT(w)	(*(int *)&(w))	/* convert union wait to int */
#define	WCOREFLAG	0200
#endif

#define	_WSTATUS(x)	(_W_INT(x) & 0177)
#define	_WSTOPPED	0177		/* _WSTATUS if process is stopped */
#define WIFSTOPPED(x)	(_WSTATUS(x) == _WSTOPPED)
#define WSTOPSIG(x)	(_W_INT(x) >> 8)
#define WIFSIGNALED(x)	(_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
#define WTERMSIG(x)	(_WSTATUS(x))
#define WIFEXITED(x)	(_WSTATUS(x) == 0)
#define WEXITSTATUS(x)	(_W_INT(x) >> 8)
#ifndef _POSIX_SOURCE
#define WCOREDUMP(x)	(_W_INT(x) & WCOREFLAG)

#define	W_EXITCODE(ret, sig)	((ret) << 8 | (sig))
#define	W_STOPCODE(sig)		((sig) << 8 | _WSTOPPED)
#endif
#endif
